package cn.ywang.mybatis;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.util.Properties;

/**
 * @author BeatificWang
 * @date 2019/8/21 22:45
 */
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class MyPlugin implements Interceptor {
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object result = null;
		long start = System.currentTimeMillis();
		long end;
		// 拿到被拦截方法的所有参数
		Object[] args = invocation.getArgs();
		MappedStatement ms = (MappedStatement) args[0];
		Object parameter = args[1];
		BoundSql boundSql = ms.getBoundSql(parameter);
		RowBounds rowBounds = (RowBounds) args[2];
		String sql = boundSql.getSql();
		if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
			System.out.println("执行sql：" + sql);
			result = invocation.proceed();
			end = System.currentTimeMillis();
			System.out.println("耗时时间(s)：" + (end - start) / 1000);
			return result;
		}
		int offset = rowBounds.getOffset();
		int limit = rowBounds.getLimit();
		String limitSuffix = String.format("LIMIT %d,%d", offset, limit);
		// 在SQL后加上limit语句
		sql = sql + " " + limitSuffix;

		// 自定义sqlSource
		SqlSource sqlSource = new StaticSqlSource(ms.getConfiguration(), sql, boundSql.getParameterMappings());

		// 修改原来的sqlSource
		Field field = MappedStatement.class.getDeclaredField("sqlSource");
		field.setAccessible(true);
		field.set(ms, sqlSource);
		System.out.println("执行sql：" + sql);
		result = invocation.proceed();
		end = System.currentTimeMillis();
		System.out.println("耗时时间(s)：" + (end - start) / 1000);
		return result;
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {

	}
}
